<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <!-- <script src="./promise.js"></script> -->
</body>

</html>


<script>
  class MyPromise {
    static PENDING = 'pending';
    static FULFILLED = 'fulfilled';
    static REJECTED = 'rejected';
    constructor(exec) {
      this.fulfilledCallbacks = [];
      this.rejectedCallbacks = [];
      this.state = MyPromise.PENDING;
      this.result = null;
      try {
        exec(this.resolve.bind(this), this.reject.bind(this));
      } catch (err) {
        this.reject(err);
      }
    }

    static resolve(result) {
      return new MyPromise((resolve) => {
        resolve(result);
      })
    }

    static reject(result) {
      return new MyPromise((resolve, reject) => {
        reject(result);
      })
    }

    resolve(result) {
      // 保持state不可逆
      if (this.state === MyPromise.PENDING) {
        setTimeout(() => {
          this.result = result;
          this.state = MyPromise.FULFILLED;
          // 执行所有的successCallback
          this.fulfilledCallbacks.forEach(callback => callback(this.result));
        })
      }
    }

    reject(result) {
      // 保持state不可逆
      if (this.state === MyPromise.PENDING) {
        setTimeout(() => {
          this.result = result;
          this.state = MyPromise.REJECTED;
          // 执行所有的failCallback
          this.rejectedCallbacks.forEach(callback => callback(this.result));
        })
      }
    }

    then(onFulfilled, onRejected) {
      onFulfilled = typeof (onFulfilled) === 'function' ? onFulfilled : value => value;
      onRejected = typeof (onRejected) === 'function' ? onRejected : reason => { throw reason };

      const promise = new MyPromise((resolve, reject) => {
        // 如果此时已经为fulfilled，则立即执行success回调
        if (this.state === MyPromise.FULFILLED) {
          setTimeout(() => {
            try {
              const res = onFulfilled(this.result);
              MyPromise.resolvePromise(promise, res, resolve, reject);
              return;
              if (res instanceof MyPromise) {
                res.then(resolve, reject);
              } else {
                resolve(res);
              }
            } catch (err) {
              reject(err);
            }
          })
        } else if (this.state === MyPromise.REJECTED) {
          // 如果此时已经为rejected，则立即执行fail回调
          setTimeout(() => {
            try {
              const res = onRejected(this.result);
              MyPromise.resolvePromise(promise, res, resolve, reject);
              return;
              if (res instanceof MyPromise) {
                res.then(resolve, reject);
              } else {
                reject(res);
              }
            } catch (err) {
              reject(err);
            }
          })
        } else if (this.state === MyPromise.PENDING) {
          this.fulfilledCallbacks.push(() => {
            try {
              const res = onFulfilled(this.result);
              MyPromise.resolvePromise(promise, res, resolve, reject);
              return;
              if (res instanceof MyPromise) {
                res.then(resolve, reject);
              } else {
                resolve(res);
              }
            } catch (err) {
              reject(err);
            }
          });
          this.rejectedCallbacks.push(() => {
            try {
              const res = onRejected(this.result);
              MyPromise.resolvePromise(promise, res, resolve, reject);
              return;
              if (res instanceof MyPromise) {
                res.then(resolve, reject);
              } else {
                reject(res);
              }
            } catch (err) {
              reject(err);
            }
          });
        }
      })
      return promise;
    }

    catch(onRejected) {
      return this.then(null, onRejected);
    }

    finally(callback) {
      const P = this.constructor;
      return this.then(
        // 这里不太理解
        value => P.resolve(callback()).then(() => value),
        reason => P.resolve(callback()).then(() => { throw reason }),
      )
    }

    static resolvePromise(promise, retVal, resolve, reject) {
      if (retVal instanceof MyPromise) {
        if (retVal.state === MyPromise.PENDING) {
          retVal.then(res => {
            // 递归，不管resolve中套了多少层的promise都给解析出来
            MyPromise.resolvePromise(promise, res, resolve, reject)
          }, reject);
        } else if (retVal.state === MyPromise.FULFILLED) {
          resolve(retVal.result);
        } else if (retVal.state === MyPromise.REJECTED) {
          reject(retVal.result);
        }
      } else {
        return resolve(retVal);
      }
    }

    static all(promises) {
      return new Promise((resolve, reject) => {
        const result = [];
        promises.forEach(promise => {
          promise.then(res => {
            result.push(res);
            if(thenCount === promises.length) {
              resolve(result);
            }
          }, err => {
            reject(err);
          })
        })
      })
    }

  }
  const myPromise = new MyPromise((resolve, reject) => {
    // throw '123';
    // resolve('myPromise: resolve');
    setTimeout(() => {
      resolve('12321');
    }, 200)
  });

  myPromise.then(res => {
    console.log(res);
    // return 'return promise';
    return new MyPromise((resolve, reject) => {
      setTimeout(() => {
        resolve(new MyPromise(resolve => {
          setTimeout(() => {
            resolve(new MyPromise(resolve => {
              setTimeout(() => {
                resolve('2 resolve');
              }, 100)
            }));
          }, 100)
        }));
      }, 100)
    })
  }).then(res => {
    console.log(res);
    return new MyPromise((resolve, reject) => {
      setTimeout(() => {
        reject('return promise2');
      }, 100)
    })
  }).catch(err => {
    console.log(err);
    return 'catch 1';
  }).then(res => {
    console.log(res);
    return new MyPromise((resolve, reject) => {
      setTimeout(() => {
        reject('return promise3');
      }, 100)
    })
  }).catch(err => {
    console.log(err);
    return 'qqe';
  }).then(res => {
    console.log(res);
    return new MyPromise((resolve, reject) => {
      setTimeout(() => {
        reject('return promise3');
      }, 100)
    })
  }).then(err => {
    console.log(err);
    return 'qqe';
  }).catch(res => {
    console.log(res);
    return new MyPromise((resolve, reject) => {
      setTimeout(() => {
        reject('return promise3');
      }, 100)
    })
  })




</script>